
#ifndef _ALITTLE_MESSAGE_H_
#define _ALITTLE_MESSAGE_H_

#include <string>
#include <vector>

namespace ALittle
{

#define DATA_OFSSET(data, offset) (void*)((char*)data + offset)

// ------------------------------------------------------------------------------------
template <typename T> unsigned int Message_GetTotalSize(const T& object) { return object.GetTotalSize(); }
template <> unsigned int Message_GetTotalSize<std::string>(const std::string& object);
template <> unsigned int Message_GetTotalSize<bool>(const bool& object);
template <> unsigned int Message_GetTotalSize<char>(const char& object);
template <> unsigned int Message_GetTotalSize<unsigned char>(const unsigned char& object);
template <> unsigned int Message_GetTotalSize<short>(const short& object);
template <> unsigned int Message_GetTotalSize<unsigned short>(const unsigned short& object);
template <> unsigned int Message_GetTotalSize<int>(const int& object);
template <> unsigned int Message_GetTotalSize<unsigned int>(const unsigned int& object);
template <> unsigned int Message_GetTotalSize<long>(const long& object);
template <> unsigned int Message_GetTotalSize<unsigned long>(const unsigned long& object);
template <> unsigned int Message_GetTotalSize<long long>(const long long& object);
template <> unsigned int Message_GetTotalSize<unsigned long long>(const unsigned long long& object);
template <> unsigned int Message_GetTotalSize<float>(const float& object);
template <> unsigned int Message_GetTotalSize<double>(const double& object);

// ------------------------------------------------------------------------------------
template <typename T> unsigned int Message_Serialize(const T& object, void* data) { return object.Serialize(data); }
template <> unsigned int Message_Serialize<std::string>(const std::string& object, void* data);
template <> unsigned int Message_Serialize<bool>(const bool& object, void* data);
template <> unsigned int Message_Serialize<char>(const char& object, void* data);
template <> unsigned int Message_Serialize<unsigned char>(const unsigned char& object, void* data);
template <> unsigned int Message_Serialize<short>(const short& object, void* data);
template <> unsigned int Message_Serialize<unsigned short>(const unsigned short& object, void* data);
template <> unsigned int Message_Serialize<int>(const int& object, void* data);
template <> unsigned int Message_Serialize<unsigned int>(const unsigned int& object, void* data);
template <> unsigned int Message_Serialize<long>(const long& object, void* data);
template <> unsigned int Message_Serialize<unsigned long>(const unsigned long& object, void* data);
template <> unsigned int Message_Serialize<long long>(const long long& object, void* data);
template <> unsigned int Message_Serialize<unsigned long long>(const unsigned long long& object, void* data);
template <> unsigned int Message_Serialize<float>(const float& object, void* data);
template <> unsigned int Message_Serialize<double>(const double& object, void* data);

// ------------------------------------------------------------------------------------
template <typename T> unsigned int Message_Deserialize(T& object, const void* data) {	return object.Deserialize(data); }
template <> unsigned int Message_Deserialize<std::string>(std::string& object, const void* data);
template <> unsigned int Message_Deserialize<bool>(bool& object, const void* data);
template <> unsigned int Message_Deserialize<char>(char& object, const void* data);
template <> unsigned int Message_Deserialize<unsigned char>(unsigned char& object, const void* data);
template <> unsigned int Message_Deserialize<short>(short& object, const void* data);
template <> unsigned int Message_Deserialize<unsigned short>(unsigned short& object, const void* data);
template <> unsigned int Message_Deserialize<int>(int& object, const void* data);
template <> unsigned int Message_Deserialize<unsigned int>(unsigned int& object, const void* data);
template <> unsigned int Message_Deserialize<long>(long& object, const void* data);
template <> unsigned int Message_Deserialize<unsigned long>(unsigned long& object, const void* data);
template <> unsigned int Message_Deserialize<long long>(long long& object, const void* data);
template <> unsigned int Message_Deserialize<unsigned long long>(unsigned long long& object, const void* data);
template <> unsigned int Message_Deserialize<float>(float& object, const void* data);
template <> unsigned int Message_Deserialize<double>(double& object, const void* data);

// ------------------------------------------------------------------------------------

class Message
{
public:
	virtual ~Message() { }
public:
	virtual unsigned int GetID() const { return 0; }
	virtual unsigned int GetTotalSize() const { return 0; }
	virtual unsigned int Serialize(void* data) const { return 0; }
	virtual unsigned int Deserialize(const void* data) { return 0; }
};

template <typename T>
class Array: public std::vector<T>, public Message
{
public:
	unsigned int GetID() const { return 0; }

	unsigned int GetTotalSize() const
	{
		unsigned int len = (*this).size();
		unsigned int total_size = sizeof(unsigned int);
		for (unsigned int i = 0; i < len; ++i)
			total_size += Message_GetTotalSize((*this)[i]);

		return total_size;
	}
	unsigned int Serialize(void* data) const
	{
		unsigned int len = (*this).size();
		*((unsigned int*)data) = len;

		char* current_data = (char*)data + sizeof(unsigned int);
		for (unsigned int i = 0; i < len; ++i)
			current_data += Message_Serialize((*this)[i], current_data);

		return (char*)current_data - (char*)data;
	}
	unsigned int Deserialize(const void* data)
	{
		unsigned int len = *((unsigned int*)data);
		(*this).resize(len);

		const char* current_data = (const char*)data + sizeof(unsigned int);
		for (unsigned int i = 0; i < len; ++i)
			current_data += Message_Deserialize((*this)[i], current_data);

		return (const char*)current_data - (const char*)data;
	}
};

} // ALittle

#endif // _ALITTLE_MESSAGE_H_
